%%% Copyright [heng] [litaocheng@gmail.com] 
%%% Licensed under the Apache License, Version 2.0 (the "License");
%%% you may not use this file except in compliance with the License. 
%%% You may obtain a copy of the License at 
%%%    http://www.apache.org/licenses/LICENSE-2.0 
%%% Unless required by applicable law or agreed to in writing, 
%%% software distributed under the License is distributed on an "AS IS" BASIS, 
%%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
%%% See the License for the specific language governing permissions and 
%%% limitations under the License. 

%%% the utils 
-module(heng_util).
-author('litaocheng@gmail.com').
-vsn('0.1').
-include("heng_master.hrl").

-export([update_record/4]).
-export([pos/2, keypos/3]).


%% @doc update record field
-spec update(Field :: atom(), Value :: term(), RecName :: atom(), RecValue :: tuple()) ->
    tuple().
update(Field, Value, RecName, RecValue) ->
    Fds = record_info(fields, RecName),
    case pos(Field, Fds) of
        0 ->
            RecValue; % do nothing return the original RecValue
        N ->
            setelement(N + 1, RecValue, Value)
    end.

%% @doc return the item postion in list
%%   0 - not found
%%   N > 0 - the index pos
-spec pos(Item :: term(), L :: list()) ->
    non_neg_integer().
pos(Item, L) when is_list(L) ->
    pos0(Item, L, 1).

pos0(_Item, [], _N) -> % can't find item in the list
    0;
pos0(Item, [Item|_], N) -> % find the item
    N;
pos0(Item, [_|Rest], N) ->
    pos0(Item, Rest, N + 1).

%% @doc return the postion of the item whose Nth element
%%   compares equal to Key
-spec keypos(Key :: term(), N :: pos_integer(), L :: list()) ->
    non_neg_integer().
keypos(Key, N, L) ->
    keypos0(Key, N, L, 1).

keypos0(_Key, _N, [], _Pos) ->
    0;
keypos0(Key, N, [H|Rest], Pos) ->
    if element(N, H) =:= Key ->
        Pos;
       true ->
        keypos0(Key, N, Rest, Pos+1)
    end.


-ifdef(test).
%% unit test
-record(updaterec_test,
        {
            key1,
            key2    
        }).

%% test update_record
updaterec_test_() ->
    Rec = #updaterec_test{},
    Rec1 = Rec#updaterec_test{key1 = 1},

    Rec2 = Rec#updaterec_test{key1 = 22, key2 = 23},
    Rec21 = update_record(key1, 22, updaterec_test, Rec),
    Rec22 = update_record(key2, 23, updaterec_test, Rec21),
    [
        ?_assertEqual(update_record(key1, 1, updaterec_test, Rec), 
                    Rec1),
        ?_assertEqual(Rec2, Rec22)
    ]

%% test pos
pos_test_() ->
    L = [this, is, a, list, 23],
    L2 = [],
    [
        ?_assertEqual(pos(this, L), 1),
        ?_assertEqual(pos(notexist, L), 0),
        ?_assertEqual(pos(23, L), 5),
        ?_assertEqual(pos(this, L2), 0),
        ?_assertEqual(pos(23, L2), 0)
    ].

%% test keypos
keypos_test_() ->
    L = [{key1, 1}, {key2, 2}, {key3, 3}],
    L2 = [],
    [
        ?_assertEqual(keypos(key100, 1, L), 0),
        ?_assertEqual(keypos(key1, 1, L), 1),
        ?_assertEqual(keypos(key3, 1, L), 3),
        ?_assertEqual(keypos(key100, 1, L2), 0),
        ?_assertEqual(keypos(2, 2, L), 2)
    ].
    
-endif.

